{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 分类训练"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "### 机器学习的hello world，一个新的分类算法，都会看看再MNIST的上的执行结果"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "pycharm": {
          "is_executing": false
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\u003cclass \u0027tuple\u0027\u003e\n",
            "(2051, 60000, 28, 28)\n",
            "47040000\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "IOPub data rate exceeded.\n",
            "The notebook server will temporarily stop sending output\n",
            "to the client in order to avoid crashing it.\n",
            "To change this limit, set the config variable\n",
            "`--NotebookApp.iopub_data_rate_limit`.\n",
            "\n",
            "Current values:\n",
            "NotebookApp.iopub_data_rate_limit\u003d1000000.0 (bytes/sec)\n",
            "NotebookApp.rate_limit_window\u003d3.0 (secs)\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import struct\n",
        "\n",
        "with open(\u0027./MNIST_data/train-images-idx3-ubyte\u0027, \u0027rb\u0027) as f:\n",
        "    buffer \u003d f.read(4*4)\n",
        "    head \u003d struct.unpack(\u0027\u003eiiii\u0027, buffer)\n",
        "    print(type(head))\n",
        "    print(head)\n",
        "    length \u003d head[1] * head[2] * head[3]\n",
        "    print(length)\n",
        "    buffer \u003d f.read(length)\n",
        "    print(buffer)\n",
        "    data \u003d struct.unpack(\u0027\u003e{}B\u0027.format(length), buffer)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "pycharm": {
          "is_executing": false,
          "name": "#%%\n"
        }
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "images \u003d np.reshape(data, (head[1], head[2], head[3]))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "pycharm": {
          "is_executing": false
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(60000, 28, 28)"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "images.shape"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {
        "pycharm": {
          "is_executing": false
        }
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\u003d\u003d\n",
            "text/plain": [
              "\u003cFigure size 432x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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\u003d\u003d\n",
            "text/plain": [
              "\u003cFigure size 432x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 432x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 432x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "for i in range(4):\n",
        "    plt.imshow(images[i], cmap\u003d\u0027gray\u0027)\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "pycharm": {
          "is_executing": false
        }
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\sklearn\\utils\\deprecation.py:85: DeprecationWarning: Function fetch_mldata is deprecated; fetch_mldata was deprecated in version 0.20 and will be removed in version 0.22. Please use fetch_openml.\n",
            "  warnings.warn(msg, category\u003dDeprecationWarning)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\sklearn\\utils\\deprecation.py:85: DeprecationWarning: Function mldata_filename is deprecated; mldata_filename was deprecated in version 0.20 and will be removed in version 0.22. Please use fetch_openml.\n",
            "  warnings.warn(msg, category\u003dDeprecationWarning)\n"
          ]
        }
      ],
      "source": [
        "from sklearn.datasets import fetch_mldata\n",
        "mnist \u003d fetch_mldata(\u0027MNIST original\u0027, data_home\u003d\u0027./\u0027)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "pycharm": {
          "is_executing": false,
          "name": "#%%\n"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{\u0027DESCR\u0027: \u0027mldata.org dataset: mnist-original\u0027,\n",
              " \u0027COL_NAMES\u0027: [\u0027label\u0027, \u0027data\u0027],\n",
              " \u0027target\u0027: array([0., 0., 0., ..., 9., 9., 9.]),\n",
              " \u0027data\u0027: array([[0, 0, 0, ..., 0, 0, 0],\n",
              "        [0, 0, 0, ..., 0, 0, 0],\n",
              "        [0, 0, 0, ..., 0, 0, 0],\n",
              "        ...,\n",
              "        [0, 0, 0, ..., 0, 0, 0],\n",
              "        [0, 0, 0, ..., 0, 0, 0],\n",
              "        [0, 0, 0, ..., 0, 0, 0]], dtype\u003duint8)}"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "mnist"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {
          "metadata": false,
          "name": "#%% md\n"
        }
      },
      "source": "* DESCR 数据集描述\n* data 包含一个数组，每个实例为一行，每个特征为一列\n* target 包含一个带有标签的数组"
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "X, y \u003d mnist[\u0027data\u0027], mnist[\u0027target\u0027]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(70000, 784)"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "X.shape"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(70000,)"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y.shape"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "%matplotlib inline\n",
        "import matplotlib\n",
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "some_digit \u003d X[36000]\n",
        "some_digit_image \u003d some_digit.reshape(28, 28)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 432x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.imshow(some_digit_image, cmap \u003d matplotlib.cm.binary)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "5.0"
            ]
          },
          "execution_count": 18,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y[36000]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 建立测试集和训练集"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "X_train, X_test, y_train, y_test \u003d X[:60000], X[60000:], y[:60000], y[60000:]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 将数据集合交叉洗牌，交叉验证时，每个子集合数据分布均匀，有些机器学习算法对训练实例的顺序敏感\n",
        "import numpy as np\n",
        "shuffle_index \u003d np.random.permutation(60000)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([ 8629, 53971, 10699, ..., 54386, 32908, 58301])"
            ]
          },
          "execution_count": 21,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "shuffle_index"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "X_train, y_train \u003d X_train[shuffle_index], y_train[shuffle_index]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[0, 0, 0, ..., 0, 0, 0],\n",
              "       [0, 0, 0, ..., 0, 0, 0],\n",
              "       [0, 0, 0, ..., 0, 0, 0],\n",
              "       ...,\n",
              "       [0, 0, 0, ..., 0, 0, 0],\n",
              "       [0, 0, 0, ..., 0, 0, 0],\n",
              "       [0, 0, 0, ..., 0, 0, 0]], dtype\u003duint8)"
            ]
          },
          "execution_count": 23,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "X_train"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 训练一个二元分类器"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([False, False, False, ..., False,  True, False])"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 识别数字5 ，二元分类5或者非5\n",
        "# 创建目标向量\n",
        "y_train_5 \u003d (y_train \u003d\u003d 5)\n",
        "y_train_5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[False, False, False, ..., False, False, False],\n",
              "       [False, False, False, ..., False, False, False],\n",
              "       [False, False, False, ..., False, False, False],\n",
              "       ...,\n",
              "       [False, False, False, ...,  True, False, False],\n",
              "       [False, False, False, ..., False, False, False],\n",
              "       [False, False, False, ..., False,  True, False]])"
            ]
          },
          "execution_count": 25,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y_train_5.reshape(20, -1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "y_test_5 \u003d (y_test \u003d\u003d 5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([ True])"
            ]
          },
          "execution_count": 27,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# SGD 梯度下降 分类器， 适合非常大的数据集，独立处理训练集数据，一次一个，适合在线学习\n",
        "from sklearn.linear_model import SGDClassifier\n",
        "sgd_clf \u003d SGDClassifier(random_state \u003d 42)\n",
        "sgd_clf.fit(X_train, y_train_5)\n",
        "sgd_clf.predict([some_digit])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "# 性能考核"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 使用交叉验证测量精度"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 评估分类器比评估回归器要困难得多\n",
        "# 3个折叠，正确率达到 95% 以上"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([0.9697 , 0.96555, 0.95935])"
            ]
          },
          "execution_count": 29,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from sklearn.model_selection import cross_val_score\n",
        "cross_val_score(sgd_clf, X_train, y_train_5, cv\u003d3, scoring\u003d\"accuracy\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 把每张图都分类成 非5\n",
        "from sklearn.base import BaseEstimator\n",
        "\n",
        "class Never5Classifier(BaseEstimator):\n",
        "    def fit(self, X, y\u003dNone):\n",
        "        pass\n",
        "    def predict(self, X):\n",
        "        return np.zeros((len(X), 1), dtype\u003dbool)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[False],\n",
              "       [False],\n",
              "       [False],\n",
              "       ...,\n",
              "       [False],\n",
              "       [False],\n",
              "       [False]])"
            ]
          },
          "execution_count": 31,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.zeros((len(X), 1), dtype\u003dbool)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([0.909  , 0.9095 , 0.91045])"
            ]
          },
          "execution_count": 32,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "never_5_clf \u003d Never5Classifier()\n",
        "cross_val_score(never_5_clf, X_train, y_train_5, cv\u003d3, scoring\u003d\"accuracy\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "* 准确率超过90% ，因为5的图像大约只有10%，你猜一张图不是5， 90%的时间你都是正确的\n",
        "* 这说明准确率无法成为分类器的首要性能指标，特别是当你处理偏科数据集， 某些类比其他类更为频繁"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 混淆矩阵"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 评估分类器性能的更好方法是混淆矩阵\n",
        "# A类别实例被分为B类别次数\n",
        "# 想要知道分类器将数字3和数字5混淆多少次，通过混淆矩阵的5行3列\n",
        "\n",
        "from sklearn.model_selection import cross_val_predict\n",
        "\n",
        "y_train_pred \u003d cross_val_predict(sgd_clf, X_train, y_train_5, cv\u003d3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "### 与 cross_val_score 相比\n",
        "* 同样执行交叉验证\n",
        "* 返回的不是评估分数，是每个折叠的预测\n",
        "* 每一个实例在模型预测时使用的数据，在训练期间从未见过"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[53484,  1095],\n",
              "       [ 1013,  4408]], dtype\u003dint64)"
            ]
          },
          "execution_count": 34,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from sklearn.metrics import confusion_matrix\n",
        "\n",
        "confusion_matrix(y_train_5, y_train_pred)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "### 行表示实际类别，列表示预测类别\n",
        "* 第一行 第一列 53272 被正确的分为 非5 ，真负类\n",
        "* 第一行 第二列 1307 被错误的分类成 5 ，假正类\n",
        "* 第二行 第一列 1077 张被错误的分为 非5， 假负类\n",
        "* 第二行 第二列 4344 张被正确的分在了5 ，真正类\n",
        "* 这种衡量方式太复杂，我们可以用更简单的指标"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[54579,     0],\n",
              "       [    0,  5421]], dtype\u003dint64)"
            ]
          },
          "execution_count": 35,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y_train_perfect_predictions \u003d y_train_5\n",
        "confusion_matrix(y_train_5, y_train_perfect_predictions)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "\n",
        "\n",
        "\n",
        "## 正类预测的准确率 被称为分类器的精度\n",
        "\n",
        "\n",
        "$\n",
        "\\text{精度} \u003d \\cfrac{TP}{TP + FP}\n",
        "$\n",
        "\n",
        "TP是真正类的数量，FP是假正类的数量\n",
        "\n",
        "\n",
        "\n",
        "$\n",
        "\\text{召回率TPR} \u003d \\cfrac{TP}{TP + FN}\n",
        "$\n",
        "* 检测正类实例的比例\n",
        "FN是假负类的数量\n",
        "![jupyter](./zhaohui.jpg)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 精度和召回率"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.801017626749046"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from sklearn.metrics import precision_score, recall_score\n",
        "\n",
        "precision_score(y_train_5, y_train_pred) # 4327 / 4327 + 1276"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.8131341080981369"
            ]
          },
          "execution_count": 37,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "recall_score(y_train_5, y_train_pred)    #  4327 / 4327 + 1094"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 说明 检测一张图的时候，只有90%的概率是准确的，而且只有64%的数字5 被它检测出来\n",
        "# 精度和召回率合成单一指标，成为 F1 分数，谐波平均值\n",
        "# 平均值平等对待所有的值，谐波平均值会给予较低值更高的权重，只有召回率和精度都很高时，才能获得较高的F1分数"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "$\n",
        "F_1 \u003d \\cfrac{2}{\\cfrac{1}{\\text{precision}} + \\cfrac{1}{\\text{recall}}} \u003d 2 \\times \\cfrac{\\text{precision}\\, \\times \\, \\text{recall}}{\\text{precision}\\, + \\, \\text{recall}} \u003d \\cfrac{TP}{TP + \\cfrac{FN + FP}{2}}\n",
        "$"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 41,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.8070303917978763"
            ]
          },
          "execution_count": 41,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from sklearn.metrics import f1_score\n",
        "\n",
        "f1_score(y_train_5, y_train_pred)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# F1分数对那些具有相近精度和召回率 分类器更有利，这不一定符合你的期望\n",
        "# 有时候你更关心精度，有时你能关心召回率\n",
        "# 训练一个分类器检测儿童可以放心观看的视频，你可能要求拦截了很多好的视频，低召回率，保留下来的都是安全的视频，高精度\n",
        "# 不能同时增加精度并减少召回率，反之亦然"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 精度/召回率权衡"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "![jupyter](./quanheng.jpg)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "* SGDClassifier对每个实例基于决策函数计算一个分值，大于阀值为正类，否则为负类\n",
        "* 中间阀值右侧找到4个真正类 真5 ， 一个假正类 6， 精度为 4/5 80%\n",
        "* 在所有的6个 真正的5 中，分类器找到了4个，召回率为 4/6 67%\n",
        "* 提高阀值，向右移动，精度提高，召回降低\n",
        "* 反之阀值降低，召回提高，精度降低\n",
        "* SKlearn不可以直接设置阀值，可以访问决策分数\n",
        "* SGDClassifier 默认阀值为0 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 如何设置阀值\n",
        "\n",
        "# 用predict_proba得到每个实例属于正类的概率，然后对概率切一下。以LogisticRegression为例\n",
        "# clf \u003d LogisticRegression()\n",
        "# clf.fit(X_train, y_train)\n",
        "# pred_proba \u003d clf.predict_proba(X_test)[:, 1]\n",
        "# threshold \u003d 0.75  # 阀值设置为0.75\n",
        "# pred_label \u003d pred_proba \u003e threshold\n",
        "\n",
        "# pred_proba是每个实例为真的概率\n",
        "# 假设阈值是0.75\n",
        "# pred_label里True就是概率大于0.75的"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([1044.06014542])"
            ]
          },
          "execution_count": 44,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 返回决策值decision_function\n",
        "\n",
        "y_scores \u003d sgd_clf.decision_function([some_digit])\n",
        "y_scores"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "threshold \u003d 0\n",
        "y_some_digit_pred \u003d (y_scores \u003e threshold)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([ True])"
            ]
          },
          "execution_count": 46,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y_some_digit_pred"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([False])"
            ]
          },
          "execution_count": 47,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 提高阀值可以降低召回率，提高阀值到200000，就错了这个图\\n\",\n",
        "threshold \u003d 200000\n",
        "y_some_digit_pred \u003d (y_scores \u003e threshold)\n",
        "y_some_digit_pred"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 49,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 如何决定使用什么阀值\n",
        "# 返回决策值，而不是预测结果\n",
        "\n",
        "y_scores \u003d cross_val_predict(sgd_clf, X_train, y_train_5, cv\u003d3, method\u003d\"decision_function\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 50,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(60000,)"
            ]
          },
          "execution_count": 50,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 有了y_scores，可以计算所有可能的阀值的精度和召回率\n",
        "\n",
        "y_scores.shape"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 51,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "from sklearn.metrics import precision_recall_curve\n",
        "\n",
        "precisions, recalls, thresholds \u003d precision_recall_curve(y_train_5, y_scores)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 53,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 576x288 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "# 使用matplotlib 绘制精度和召回相对于阀值的函数图\n",
        "def plot_precision_recall_vs_threshold(precisions, recalls, thresholds):\n",
        "    plt.plot(thresholds, precisions[:-1], \"b--\", label\u003d\"Precision\", linewidth\u003d2)\n",
        "    plt.plot(thresholds, recalls[:-1], \"g-\", label\u003d\"Recall\", linewidth\u003d2)\n",
        "    plt.xlabel(\"Threshold\", fontsize\u003d16)\n",
        "    plt.legend(loc\u003d\"upper left\", fontsize\u003d16)\n",
        "    plt.ylim([0, 1])\n",
        "               \n",
        "plt.figure(figsize\u003d(8, 4))\n",
        "plot_precision_recall_vs_threshold(precisions, recalls, thresholds)\n",
        "plt.xlim([-700000, 700000])\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 54,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "findfont: Font family [\u0027sans-serif\u0027] not found. Falling back to DejaVu Sans.\n",
            "findfont: Font family [\u0027sans-serif\u0027] not found. Falling back to DejaVu Sans.\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 21484 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 22238 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 21484 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 22238 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 31934 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 24230 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 31934 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 24230 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n"
          ]
        },
        {
          "data": {
            "image/png": "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\u003d\u003d\n",
            "text/plain": [
              "\u003cFigure size 576x432 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.rcParams[\u0027font.sans-serif\u0027] \u003d [\u0027SimHei\u0027]\n",
        "\n",
        "def plot_precision_vs_recall(precisions, recalls):\n",
        "    plt.plot(recalls, precisions, \"b-\", linewidth\u003d2)\n",
        "    plt.xlabel(\"召回\", fontsize\u003d16)\n",
        "    plt.ylabel(\"精度\", fontsize\u003d16)\n",
        "    plt.axis([0, 1, 0, 1])\n",
        "    \n",
        "plt.figure(figsize\u003d(8, 6))\n",
        "plot_precision_vs_recall(precisions, recalls)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 通过选择阀值来实现最佳的精度/召回率权衡"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 目标设定为90%的精度，阀值大概在30000左右 , 设置了阀值为30000\n",
        "y_train_pred_90 \u003d (y_scores \u003e 30000)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 56,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.9375"
            ]
          },
          "execution_count": 56,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "precision_score(y_train_5, y_train_pred_90)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 57,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.005534034311012728"
            ]
          },
          "execution_count": 57,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "recall_score(y_train_5, y_train_pred_90)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 总结\n",
        "* 获得了一个90%精度的分类器，但如果召回太低，精度再高，也不怎么有用\n",
        "* 如果工作中，需要99%的精度，你应该回应，召回率是多少？"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## ROC 曲线"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 58,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 本质是 真正类率tpr和假正类率fpr（错误的分为正类的负类实例比例）\n",
        "# 与召回/精度曲线非常相似"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "from sklearn.metrics import roc_curve\n",
        "\n",
        "fpr, tpr, thresholds \u003d roc_curve(y_train_5, y_scores)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 20551 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 27491 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 31867 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 29575 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 20551 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 27491 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 31867 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 29575 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 30495 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 30495 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n"
          ]
        },
        {
          "data": {
            "image/png": "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LFy4kEsuucTpSJVKxR+knIJiRr284eRyuj/sUI//d/sPwvo4j4iIfNv48eN5/vnnueKKK3jllVdo3ry505EqnVaNCcLf1u7g0if+ebL02zdIVOmLiLhQly5d+MUvfsHKlStdWfqgEf85rfzqID9f8vnJx08NvYS07s1U+iIiLmCtZebMmdSpU4dbb72VUaNGOR2pymnEfxZbdmdzx//bAMBFDWuS+Ztrufmy5ip9EREXOHz4MIMGDWLSpEksX77c6Tgho+I/gxKfn8GzVp98vHj85URpPX0REVf44IMP6NSpE//85z+ZOXMmr7zyitORQkZT/Wcw5Pn/lf68uy4jLtrrYBoREaksX375JVdffTXt2rXjrbfeIjU11elIIaUhbDl+u+I/fLY3Bwista9FeUREwl9+fj4AF110EX/5y1/YuHFjxJU+qPi/48VV25n9720AdGpWi18P+b7DiURE5EItXLiQVq1asWlTYMXVW2+9lcTERIdTOUPFf4olGXv59bIvALjukoYsHtfL4UQiInIh8vPzGTduHMOGDaNZs2auWX3vQqj4SxWV+Jn4asbJx8+lddHZ+yIiYezzzz+ne/fuvPDCCzzwwAOsXr2aNm3aOB3LcTq5r9Tt/+/jkx9//OjVurueiEiYe+ONNzhw4AArVqygf//+TsepNjTiB44XFLNm6xEAftb/IurXjHM4kYiIVER2djbp6ekAPPbYY3z66acq/dNoxA/cOnf9yY/v7tvawSQiIlJRa9euJS0tDb/fT2ZmJjExMTRo0MDpWNVOxI/4n/8gky17jgHwhxGpOq4vIhJm/H4/v/3tb+nduzfGGN544w1iYmKcjlVtRfSI/6P/HmLq218B0KZeAkM6N3E4kYiInI/jx49zww038O677zJixAhmz55NcnKy07GqtYgt/uMFxYx6eSMAsVEe3p3c1+FEIiJyvhITE6lduzZz587lzjvv1KxtECJ2qv+NjXso8vkBWPPQVfphEREJE0VFRTzyyCPs2LEDYwyvvfYao0aN0vt4kCKy+K21zP5wKwCPDfgedRJjHU4kIiLByMzMpFevXvz2t79l6dKlTscJSxE51f/x9iwO5BQS5THc2qOF03FERCQIf//737nnnnuIjo5m0aJFDBkyxOlIYSniRvzWWp5a/h8A+rSvp7vuiYiEgRdffJHbbruNzp07s2XL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\u003d\u003d\n",
            "text/plain": [
              "\u003cFigure size 576x432 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.rcParams[\u0027font.sans-serif\u0027] \u003d [\u0027SimHei\u0027]\n",
        "def plot_roc_curve(fpr, tpr, label\u003dNone):\n",
        "    plt.plot(fpr, tpr, linewidth\u003d2, label\u003dlabel)\n",
        "    plt.plot([0, 1], [0, 1], \u0027k--\u0027)\n",
        "    plt.axis([0, 1, 0, 1])\n",
        "    plt.xlabel(\u0027假正类率\u0027, fontsize\u003d16)\n",
        "    plt.ylabel(\u0027真正类率\u0027, fontsize\u003d16)\n",
        "\n",
        "plt.figure(figsize\u003d(8, 6))\n",
        "plot_roc_curve(fpr, tpr)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.9676792989245759"
            ]
          },
          "execution_count": 61,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 计算曲线下面积AUC，虚线是随机分类0.5到1\n",
        "from sklearn.metrics import roc_auc_score\n",
        "\n",
        "roc_auc_score(y_train_5, y_scores)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "* 召回率TPR越高，分类器的假正类FPR就越多\n",
        "* 虚线表示纯随机分类器的ROC曲线，好的分类器应该远离这条线，向左上角\n",
        "* 是使用精度/召回率 PR曲线，还是使用ROC，关键在于 正类非常少或者更关注假正类而不是假负类，选择PR，反之ROC\n",
        "* 例如：前面例子ROC曲线很不错是因为跟负类 非5 相比， 正类 数据5 数量真的很少"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 训练随机森林分类器，比较SGD分类器的ROC曲线和ROC AUC分数"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "* 获取训练集中每个实例的分数\n",
        "* RandomForestClassifier 没有descision_function(),但是拥有dict_proda()方法，sklearn中分类器都有这两个中的一个\n",
        "* dict_proda返回一个矩阵，每行一个实例，每列代表一个类别的概率，比如这个图片 70%是5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "from sklearn.ensemble import RandomForestClassifier\n",
        "\n",
        "forest_clf \u003d RandomForestClassifier(n_estimators\u003d10, random_state\u003d42)\n",
        "y_probas_forest \u003d cross_val_predict(forest_clf, X_train, y_train_5, cv\u003d3, method\u003d\"predict_proba\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[1. , 0. ],\n",
              "       [1. , 0. ],\n",
              "       [1. , 0. ],\n",
              "       ...,\n",
              "       [1. , 0. ],\n",
              "       [0.6, 0.4],\n",
              "       [1. , 0. ]])"
            ]
          },
          "execution_count": 63,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y_probas_forest"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# 绘制ROC曲线，需要决策值不是概率，直接使用正类的概率作为决策值：\n",
        "y_scores_forest \u003d y_probas_forest[:, 1]\n",
        "fpr_forest, tpr_forest, thresholds_forest \u003d roc_curve(y_train_5,y_scores_forest)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 65,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([0. , 0. , 0. , ..., 0. , 0.4, 0. ])"
            ]
          },
          "execution_count": 65,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "y_scores_forest"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 66,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 20551 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 27491 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 31867 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 29575 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 20551 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 27491 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 31867 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 29575 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:211: RuntimeWarning: Glyph 30495 missing from current font.\n",
            "  font.set_text(s, 0.0, flags\u003dflags)\n",
            "c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\backends\\backend_agg.py:180: RuntimeWarning: Glyph 30495 missing from current font.\n",
            "  font.set_text(s, 0, flags\u003dflags)\n"
          ]
        },
        {
          "data": {
            "image/png": "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q66v7N/fuad9o0ZQp06WHFJERHKA3377jRYtWlC1alW++OILIiIi3I7kU55o8SckWQDCC2dNN/+SJfDuuzBgQNpleyIikrudPevMBbvhhht4//33WbNmTZ4r+uCZwp/W4s8Kt93m3GXv+echMjJLDikiIi6aOXMmFStWZO3atQDcd999FChQwOVU7vBY4b+2Fv/vv8OJE87XFSrASy9dYzAREXHV2bNneeSRR+jSpQtly5b1zOp718Ijhd/p6i8RFpzpY8THww03QMuWMHlyViUTERG3bNiwgYYNGzJhwgSeeOIJli9fTuXKld2O5TpPTO5Ltk7hLxCc+bcTEwP9+sGkSTBvXlYlExERt3z++eccOHCAhQsX0rp1a7fj5BieaPHblMIfGuif6WMUKwZvvunccKdUqaxKJiIivnT8+HGioqIAePbZZ/n5559V9M/jicKf7NR98gVlrsW/d6/zOShIN9wREcmtVq5cSUREBB06dCA+Pp6AgABKlizpdqwcxxOFPyml8ocGXX2L/6OPoHRpZznehISsTiYiItktOTmZkSNH0qxZM4wxfP755wQFBbkdK8fyxBh/Sk9/prr627RxPq9bB4GBWRhKRESy3cmTJ+ncuTNff/01PXr04J133qFQoUJux8rRPNHiT53cly8TLf6iReGDD5yxfRERyV0KFChA0aJFmTx5Mh9//LGKfgbk2cKfer0+wH33aR1+EZHcIj4+nhEjRrB9+3aMMXz66ac89NBDWbZku9d5pPA7nzM6xm8t1KgBNWvCqlXZGExERLLU5s2badKkCSNHjmTu3Llux8mVPDHGn9biz9jb2bcPzpyBgwehdu3sTCYiIlnlww8/5OGHHyYwMJBZs2bRsWNHtyPlSp5o8QMEBfjh75exbp7wcDh0CJYvh9Csua+PiIhkoylTpvCXv/yFunXrsn79ehX9a+CJFj9c/Yz+gABo2DCbwoiISJZISkrC39+fHj16cPLkSR599FECAjxTulzhmRZ/Rif2ff45/O9/Tle/iIjkTNZaxo4dS8OGDTlz5gwFChQgMjJSRT8LeKbwZ2Ri35EjzkI9rVo5d+ITEZGc59ChQ7Rr147IyEhKly5NXFyc25E8xTN/OmWkxR8XBy++6PwBULdu9mcSEZGr8+2339K7d2+OHDnCuHHjePTRR3WZXhbzTuEPvPJbCQ+HESN8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F6lZsya9evWib9++bkcSEREP80xXf260Y8cObr31Vv75z3/yww8/uB1HRETyAM+0+HObGTNm0KdPH5KSkpg2bRq9evVyO5KIiOQBnmnxr1jpdoKMW7t2LV27dqVq1apERUWp6IuIiM94pvDnBidPngSgfv36fP755yxbtozKlSu7nEpERPISzxT+xo3cTnBp1lomTZpE+fLlWb9+PQBdu3a9YPENERGR7OaZwp9Tr3w7fvw43bt3p3///jRo0ICSJUu6HUlERPIwzxT+nGjlypVEREQwe/ZsXnvtNRYtWvTnTTVERETc4JnC/8cfbie40Ny5c/Hz82PZsmU89dRT+Pl55tstIj4wdepUjDF/fgQFBVG5cmVGjBhBbGysK5lefPHFHLO42Pnfn/QfX3/9tdvxLjB16lTee+89t2N453K+4yfcTuDYu3cv+/bto379+rz88ssMGzaMQoUKuR1LRHKxzz//nDJlynDy5ElmzZrFyJEjOXnyJG+++abb0XKE1O9PejVq1HApzaVNnTqVxMREHnzwQVdzeKbwV63qdgL44osvuP/++ylatCgbN24kMDBQRV9ErllERMSfd9a788472bRpE1OmTGHs2LHqSeTc709WiouLu+BWxl7gmZ+YIoXdO3dcXByDBw/mnnvuITw8nDlz5uDv7+9eIBHxtHr16nH27FkOHz7857ZDhw7Rv39/qlWrRr58+Shbtiz33nsve/bsOee1qV31mzZtom3bthQoUIDy5cvz8ssvk5ycfM6+UVFRNGvWjJCQEEqXLs3f//53LnZH15iYGB599FHCw8MJDg6mevXqjBkz5px9lyxZgjGG2bNn079/f4oWLUqRIkUYPHgwSUlJrF69mqZNm5I/f35q1qzJl19+mWXfr99//51OnTpR+P/bu/egqOt+gePvL4qi3Am8hdapJ0XFW+OFkhHyQiAlo2maYYrag+YloXHQcQatQ/YoiZpG2slHO6e8PGYeL2jOKU2i4JnKzNHSxlN4wwsB5Y1HXfieP3bZw7IIC7KLu/t5zeywv99+f9/97oed/fwu3/1sQABt2rQhIiKCzz77rNa4HD9+nKeffhofHx+ef/558+OffvopERERtG3bloCAAMaNG8fZs2ct+ti8eTP9+vXDx8cHf39/evXqxfr16wGIjo7m8OHDfP311+bLEdHR0U32GhvCZY74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\u003d\u003d\n",
            "text/plain": [
              "\u003cFigure size 576x432 with 1 Axes\u003e"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.figure(figsize\u003d(8, 6))\n",
        "plt.plot(fpr, tpr, \"b:\", linewidth\u003d2, label\u003d\"SGD\")\n",
        "plot_roc_curve(fpr_forest, tpr_forest, \"Random Forest\")\n",
        "plt.legend(loc\u003d\"lower right\", fontsize\u003d16)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 67,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.9915693979113501"
            ]
          },
          "execution_count": 67,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Rand 比SGD 好很多，ROC AUC的分数也高很多\n",
        "roc_auc_score(y_train_5, y_scores_forest)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.9844195742813254"
            ]
          },
          "execution_count": 68,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 再看一下 精度和召回率 也很高\n",
        "y_train_pred_forest \u003d cross_val_predict(forest_clf, X_train, y_train_5, cv\u003d3)\n",
        "precision_score(y_train_5, y_train_pred_forest)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "0.8275225973067699"
            ]
          },
          "execution_count": 69,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "recall_score(y_train_5, y_train_pred_forest)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 总结\n",
        "* 选择合适的指标利用交叉验证来对分类器进行评估\n",
        "* 选择满足需求的精度/召回率权衡\n",
        "* 使用ROC曲线和ROC AUC分数比较多个模型"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 多类别分类器\n",
        "* 尝试5 之外的检测\n",
        "* 多类别分类器 区分两个以上的类别\n",
        "* 随机森里和朴素贝叶斯可以直接处理多个类别\n",
        "* 支持向量机svm和线性分类器只可以处理二元分类器"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 解决方案\n",
        "1. 将数字图片分类0到9，训练10个二元分类器，每个数字一个，检测一张图片时，获取每个分类器的决策分数，哪个最高属于哪个，称为一对多OvA\n",
        "2. 为每一对数字训练一个二元分类器，区分0，1 区分0，2 区分1，2 称为一对一OvO策略，存在N个类别，需要N*（N-1）/2个分类器，最后看哪个类别获胜最多"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "### 优缺点\n",
        "* OvO 只需要用到部分训练集对其必须区分两个类别进行训练\n",
        "* 对于较小训练集合OvO比较有优势， 大训练集合 OvA 速度快，所以OvA更常用，比如svm 在数据规模扩大时表现糟糕\n",
        "* sklearn 检查到使用二元分类算法进行多类别分类任务，会自动运行OvA，SVM分类器除外"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([5.])"
            ]
          },
          "execution_count": 70,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "sgd_clf.fit(X_train, y_train)\n",
        "sgd_clf.predict([some_digit])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 71,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[-18201.50353337, -30535.98923154, -10880.9323987 ,\n",
              "          -401.42517108, -12813.98862409,   1125.88890176,\n",
              "        -37326.63819682, -20012.47015584, -10723.44354228,\n",
              "        -14096.70015627]])"
            ]
          },
          "execution_count": 71,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 内部实际上训练了10个二元分类器，获得图片的决策分数，然后选择了分数最高的类别\n",
        "# 返回10个分数，每个类别1个\n",
        "some_digit_scores \u003d sgd_clf.decision_function([some_digit])\n",
        "some_digit_scores"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 72,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "5"
            ]
          },
          "execution_count": 72,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.argmax(some_digit_scores)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 73,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])"
            ]
          },
          "execution_count": 73,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 目标类别列表会存储在classes_这个属性中，按值大小排列\n",
        "sgd_clf.classes_"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 74,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "5.0"
            ]
          },
          "execution_count": 74,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "sgd_clf.classes_[np.argmax(some_digit_scores)]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 75,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([5.])"
            ]
          },
          "execution_count": 75,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 使用OvO策略，一对一或者一对多\\n\",\n",
        "from sklearn.multiclass import OneVsOneClassifier\n",
        "\n",
        "ovo_clf \u003d OneVsOneClassifier(SGDClassifier(max_iter\u003d5, tol\u003d-np.infty, random_state\u003d42))\n",
        "ovo_clf.fit(X_train, y_train)\n",
        "ovo_clf.predict([some_digit])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 77,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "45"
            ]
          },
          "execution_count": 77,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "len(ovo_clf.estimators_)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 78,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([5.])"
            ]
          },
          "execution_count": 78,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 使用随机森林\n",
        "forest_clf.fit(X_train, y_train)\n",
        "forest_clf.predict([some_digit])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 79,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([[0.1, 0. , 0.1, 0. , 0. , 0.8, 0. , 0. , 0. , 0. ]])"
            ]
          },
          "execution_count": 79,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# 随机森林直接将实例分为多个类别，调用predict_proba()可以获得分类器将每个实例分类为每个类别的概率列表\n",
        "forest_clf.predict_proba([some_digit])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "pycharm": {}
      },
      "source": [
        "## 评估分类器"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "pycharm": {}
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.4"
    },
    "pycharm": {
      "stem_cell": {
        "cell_type": "raw",
        "metadata": {
          "collapsed": false
        },
        "source": []
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}